﻿
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
namespace YoucaiReader.Helper.Drawing
{
    public class GeneralPathImpl : GeneralPath
    {
        private int cacheId;
        private PathData data;
        private static Dictionary<int, PathData> dataCache;
        private static int MAX_PATH_CACHE = 0x2328;
        private static Dictionary<int, List<Path>> pathCache;
        private static int pathCacheCount;

        public GeneralPathImpl()
        {
            this.data = new PathData(true);
        }

        public GeneralPathImpl(int cacheId, int[] xCoords, int[] yCoords, int coordOffset, int numCoords, int[] contourEnds, int contourOffset, int numContours)
        {
            this.cacheId = cacheId;
            if (dataCache == null)
            {
                dataCache = new Dictionary<int, PathData>();
            }
            if (dataCache.ContainsKey(this.cacheId))
            {
                this.data = dataCache[this.cacheId];
            }
            else
            {
                this.data = new PathData(true);
                if (numCoords != (contourEnds[(contourOffset + numContours) - 1] + 1))
                {
                    throw new ArgumentException();
                }
                int index = coordOffset;
                for (int i = contourOffset; i < (contourOffset + numContours); i++)
                {
                    int num3 = contourEnds[i] + coordOffset;
                    int num4 = (num3 - index) + 1;
                    if ((num4 % 3) != 0)
                    {
                        throw new ArgumentException("Expected all cubic edges.");
                    }
                    int num5 = xCoords[index];
                    int num6 = yCoords[index];
                    this.moveTo((float)num5, (float)num6);
                    index++;
                    while (index <= (num3 - 1))
                    {
                        int num7;
                        int num8;
                        if ((index + 2) > num3)
                        {
                            num7 = num5;
                            num8 = num6;
                        }
                        else
                        {
                            num7 = xCoords[index + 2];
                            num8 = yCoords[index + 2];
                        }
                        this.curveTo((float)xCoords[index], (float)yCoords[index], (float)xCoords[index + 1], (float)yCoords[index + 1], (float)num7, (float)num8);
                        index += 3;
                    }
                    index--;
                }
                dataCache.Add(this.cacheId, this.data);
            }
        }

        private void AddBounds(float x, float y)
        {
            if (this.data.pMin.X > x)
            {
                this.data.pMin.X = ((double)x);
            }
            if (this.data.pMin.Y > y)
            {
                this.data.pMin.Y = ((double)y);
            }
            if (this.data.pMax.X < x)
            {
                this.data.pMax.X = ((double)x);
            }
            if (this.data.pMax.Y < y)
            {
                this.data.pMax.Y = ((double)y);
            }
        }

        internal static void ClearCache()
        {
            if (pathCache != null)
            {
                foreach (List<Path> list in pathCache.Values)
                {
                    list.Clear();
                }
                pathCache.Clear();
                pathCache = null;
            }
            if (dataCache != null)
            {
                dataCache.Clear();
                dataCache = null;
            }
        }

        public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
        {
            CurvePoints item = new CurvePoints
            {
                p1 = new Point((double)x1, (double)y1),
                p2 = new Point((double)x2, (double)y2),
                p3 = new Point((double)x3, (double)y3)
            };
            this.data.points.Add(item);
            this.AddBounds(x1, y1);
            this.AddBounds(x2, y2);
            this.AddBounds(x3, y3);
        }

        public Rectangle getBounds()
        {
            double introduced0 = this.data.pMax.X;
            double introduced1 = this.data.pMax.Y;
            return new Rectangle((int)Math.Floor(this.data.pMin.X), (int)Math.Floor(this.data.pMin.Y), (int)Math.Ceiling((double)(introduced0 - this.data.pMin.X)), (int)Math.Ceiling((double)(introduced1 - this.data.pMin.Y)));
        }

        public Path getPath()
        {
            List<Path> list;
            if (pathCache == null)
            {
                pathCache = new Dictionary<int, List<Path>>();
            }
            if (pathCache.ContainsKey(this.cacheId))
            {
                list = pathCache[this.cacheId];
            }
            else
            {
                list = new List<Path>();
                pathCache.Add(this.cacheId, list);
            }
            foreach (Path path in list)
            {
                if (path.Parent == null)
                {
                    return path;
                }
            }
            Path item = new Path();
            PathGeometry geometry = new PathGeometry();
            item.Data = (geometry);
            PathFigure figure = null;
            int count = this.data.points.Count;
            for (int i = 0; i < count; i++)
            {
                object obj2 = this.data.points[i];
                if (obj2 is Point)
                {
                    PathFigure figure2 = new PathFigure();
                    figure2.IsFilled=(true);
                    figure2.StartPoint=((Point)obj2);
                    figure = figure2;
                    geometry.Figures.Add(figure);
                }
                else
                {
                    BezierSegment segment = new BezierSegment();
                    CurvePoints points = (CurvePoints)obj2;
                    segment.Point1=(points.p1);
                    segment.Point2 = (points.p2);
                    segment.Point3 = (points.p3);
                    figure.Segments.Add(segment);
                }
            }
            if (pathCacheCount <= MAX_PATH_CACHE)
            {
                list.Add(item);
                pathCacheCount++;
            }
            return item;
        }

        public void moveTo(float x, float y)
        {
            this.data.points.Add(new Point((double)x, (double)y));
            this.AddBounds(x, y);
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct CurvePoints
        {
            internal Point p1;
            internal Point p2;
            internal Point p3;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct PathData
        {
            internal List<object> points;
            internal Point pMin;
            internal Point pMax;
            internal PathData(bool init)
            {
                this.points = new List<object>();
                this.pMin = new Point(double.MaxValue, double.MaxValue);
                this.pMax = new Point(double.MinValue, double.MinValue);
            }
        }
    }
}

